/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package pacificlms.BackOffice;


import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import pacificlms.ConnectionInfo;
import pacificlms.DataHolder;
import pacificlms.Email.EmailManager;
import pacificlms.MasterConnection;
import pacificlms.Verifiable.Database.CheckOut;
import pacificlms.Verifiable.Database.Hold;
import pacificlms.Verifiable.Database.Setting;
import pacificlms.Verifiable.Database.Resource;
import pacificlms.Verifiable.Database.Member;
import pacificlms.Verifiable.VerifiableObject;
/**
 *
 * @author brian
 */
public class BackOfficeMain {

    private static GregorianCalendar GetBOSDate(Statement stmt)
    {
        Setting Set = new Setting();
        Set.Name("BOS Update");
        String SettingSQL = Set.FindIdenticalSQL();
        try
        {
            ResultSet RSSetting = stmt.executeQuery(SettingSQL);
            RSSetting.next();
            Set.FillFromResultSet(RSSetting, RSSetting.getMetaData());
            
            SimpleDateFormat sdf =new SimpleDateFormat("yyyy-MM-dd");
            Date Date = sdf.parse(Set.Value(null));
            GregorianCalendar GC = (GregorianCalendar)GregorianCalendar.getInstance();
            GC.setTime(Date);
            
            return GC;
        }
        catch(Exception Ex)
        {
            System.err.println("Error Connecting to database\n" + Ex.toString());
            return null;
        }
    }
    
    
    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        // TODO code application logic here
        SimpleDateFormat sdf =new SimpleDateFormat("yyyy-MM-dd");
        Statement stmt = null;
        Statement stmt2 = null;
        try
        {
            DriverManager.registerDriver(new com.mysql.jdbc.Driver());
            Class.forName("com.mysql.jdbc.Driver");
            
            //fixme switch
            Connection Con = DriverManager.getConnection("jdbc:mysql:" + args[0], args[1], args[2]);
            //Connection Con = DriverManager.getConnection("jdbc:mysql:" + "//localhost/cics505lms", "root", "");
            DataHolder.LoadData(Con);
            
            MasterConnection.Initialize(Con);
            Connection Conn = MasterConnection.getInstance();
            stmt = Conn.createStatement();
            stmt2 = Conn.createStatement();
        }
        catch(Exception Ex)
        {
            System.err.println("Unable to get connection\n"+Ex.toString());
            return;
        }
        
        while(true)
        {
            //get now date
            GregorianCalendar now = new GregorianCalendar();

            //check setting if BOS date is different from now date
            GregorianCalendar bosDate = GetBOSDate(stmt);

            int NowDay = now.get(GregorianCalendar.DAY_OF_YEAR);
            int NowYear = now.get(GregorianCalendar.YEAR);
            int BOSDay = bosDate.get(GregorianCalendar.DAY_OF_YEAR);
            int BOSYear = bosDate.get(GregorianCalendar.YEAR);

            if (NowDay != BOSDay || NowYear != BOSYear)//once per day
            {
                String Week2, Week1;
                GregorianCalendar DueDates = new GregorianCalendar();
                now.add(Calendar.DATE, 7);
                Week1 = sdf.format(DueDates.getTime());
                now.add(Calendar.DATE, 7);
                Week2 = sdf.format(DueDates.getTime());

                // check checkout dates
                // email people with checkout
                CheckOut CO = new CheckOut();
                CO.Finished("0");

                String CheckOutSQL = CO.FindIdenticalSQL();
                CheckOutSQL += "AND (DueDate = '"+Week1+"' OR DueDate = '"+Week2+"')";
                try
                {
                    ResultSet RSDueSoon = stmt.executeQuery(CheckOutSQL);
                    while(RSDueSoon.next())
                    {
                        CO.FillFromResultSet(RSDueSoon, RSDueSoon.getMetaData());
                        ArrayList<VerifiableObject> MembList = CO.GetRelatedData(Member.class, 1);
                        Member Memb = (Member)MembList.get(0);
                        EmailManager.CheckoutDueEmail(Memb, CO);
                    }
                }
                catch(Exception Ex)
                {
                    System.err.println("Error sending emails for due date\n"+Ex.toString());
                }

                CheckOutSQL = CO.FindIdenticalSQL();
                CheckOutSQL += "AND DueDate < '"+sdf.format(bosDate.getTime())+"'";
                try
                {
                    ResultSet RSOverDue = stmt.executeQuery(CheckOutSQL);
                    while(RSOverDue.next())
                    {
                        CO.FillFromResultSet(RSOverDue, RSOverDue.getMetaData());
                        ArrayList<VerifiableObject> MembList = CO.GetRelatedData(Member.class, 1);
                        Date Date = sdf.parse(CO.DueDate(null));
                        GregorianCalendar LateTime = (GregorianCalendar)GregorianCalendar.getInstance();
                        LateTime.setTime(Date);
                        Member Memb = (Member)MembList.get(0);
                        int DaysLate = (bosDate.get(Calendar.DAY_OF_YEAR) - LateTime.get(Calendar.DAY_OF_YEAR)) + (bosDate.get(Calendar.YEAR) - LateTime.get(Calendar.YEAR)) * 365;
                        
                        //late fine
                        double Daily = Double.parseDouble(DataHolder.GetSetting("Daily Fine").Value(null));
                        double Max = Double.parseDouble(DataHolder.GetSetting("Maximum Fine").Value(null));
                        double CurrentFine = Double.parseDouble(CO.LateFine(null));
                        CurrentFine += Daily;
                        if (CurrentFine > Max)
                            CurrentFine = Max;
                        CO.LateFine(String.valueOf(CurrentFine));
                        CO.Verify();
                        String SQLFine = CO.UpdateRecrodSQL();
                        stmt2.executeUpdate(SQLFine);
                        EmailManager.CheckoutLateEmail(Memb, CO, DaysLate);
                    }
                }
                catch(Exception Ex)
                {
                    System.err.println("Error sending emails for late resource\n"+Ex.toString());
                }


                // check hold dates
                // reset holds
                Hold Hold = new Hold();
                Hold.Finished("0");
                Hold.EndDate(sdf.format(bosDate.getTime()));//finds any holds from yesterday
                String HoldSQL = Hold.FindIdenticalSQL();
                try
                {
                    ResultSet RSDueSoon = stmt.executeQuery(HoldSQL);
                    while(RSDueSoon.next())
                    {
                        Hold FromHold = new Hold();
                        try
                        {
                            //finish hold and send notice to the next person
                            FromHold.FillFromResultSet(RSDueSoon, RSDueSoon.getMetaData());
                            FromHold.Finished("1");
                            FromHold.Verify();
                            String CloseHold = FromHold.UpdateRecrodSQL();
                            stmt2.executeUpdate(CloseHold);
                            
                            Resource Res = (Resource)FromHold.GetRelatedData(Resource.class).get(0);

                            if (!FromHold.EmailNextHolder(Res.ResourceCode(null), stmt))
                            {
                                //fixme is this a good way to tell librarian what to do
                                System.out.println("Held copy of " + Res.Title(null) + "can be returned to circulation.\n");
                            }
                        }
                        catch(Exception Ex)
                        {
                            System.err.println("Error updating hold RC:"+FromHold.ResourceCode(null) +" ID:"+FromHold.IdentityNumber(null) +"\n"+Ex.toString());
                        }
                    }
                }
                catch(Exception Ex)
                {
                    System.err.println("Error sending emails for due date\n"+Ex.toString());
                }

                //}
            }

            //update setting with next time
            try
            {
                bosDate.add(Calendar.DATE, 1);
                String NewBosDate = sdf.format(GregorianCalendar.getInstance().getTime());
                Setting BOSDate = new Setting("BOS Update", "", "");
                String SQLGetDate = BOSDate.FindIdenticalSQL();
                ResultSet RSDate = stmt.executeQuery(SQLGetDate);
                RSDate.next();
                BOSDate.FillFromResultSet(RSDate, RSDate.getMetaData());
                BOSDate.Value(NewBosDate);
                if (!BOSDate.Verify())
                {
                    throw new Exception("date error");
                }
                String SQLSetDate = BOSDate.UpdateRecrodSQL();
                stmt.executeUpdate(SQLSetDate);
            }
            catch(Exception Ex)
            {
                System.err.println("Error updating date\n"+Ex.toString());
            }
            
            //sleep 10 mins
            try
            {
                Thread.sleep(1000*60*10);
                System.out.println("Slept for 10 min\n");
            }
            catch(Exception Ex)
            {
                System.err.println("Unable to sleep\n"+Ex.toString());
            }
        }
    }
}
